/**
* File Name: produce_consumer_02.c
* Auther: Jichang
* Environment: Fedora 7 server
* many consumer.
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>

void err_thread(int ret, char *str)
{
	if(ret != 0) {
		fprintf(stderr, "%s: %s\n", str, strerror(ret));
		pthread_exit(NULL);
	}
}

struct msg {
	int num;
	struct msg *next;
};
struct msg *head;

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t has_produce = PTHREAD_COND_INITIALIZER; // considtion var

void *producer(void *arg)
{
	while(1){ 
		struct msg *mp = malloc(sizeof(struct msg));

		// simulate produce
		mp->num = rand() % 1000 + 1;
		printf("--Produce %d\n", mp->num);

		pthread_mutex_lock(&mutex);
		mp->next = head;
		head = mp; //write
		pthread_mutex_unlock(&mutex);

		// send signal
		pthread_cond_signal(&has_produce);

		sleep(rand() % 3);
	}
	return NULL;
}

void *consumer(void *arg)
{
	while(1) { 
		struct msg *mp;
		pthread_mutex_lock(&mutex);
		while(head == NULL) {
			pthread_cond_wait(&has_produce, &mutex);
		}

		// read
		mp = head;
		head = mp->next;

		pthread_mutex_unlock(&mutex);
		printf("==Consumer id: %lu: %d\n", pthread_self(), mp->num);

		free(mp);
		sleep(rand() % 3);
	}

	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t pid, cid;
	int ret = 0;

	srand(time(NULL));

	pthread_create(&pid, NULL, producer, NULL);
	if(ret != 0) {
		err_thread(ret, "pthread_error");
	}
	// consumer 1
	pthread_create(&cid, NULL, consumer, NULL);
	if(ret != 0) {
		err_thread(ret, "pthread_error");
	}
	// consumer 2
	pthread_create(&cid, NULL, consumer, NULL);
	if(ret != 0) {
		err_thread(ret, "pthread_error");
	}
	// consumer 3
	pthread_create(&cid, NULL, consumer, NULL);
	if(ret != 0) {
		err_thread(ret, "pthread_error");
	}

	pthread_join(pid, NULL);
	pthread_join(cid, NULL);
	
	return 0;
}

